package com.gavin.plugin.database.optimize.parse;

import java.sql.SQLException;
import java.util.ArrayList;

import com.gavin.model.JObject;
import com.gavin.model.Model;
import com.gavin.plugin.database.help.ValueUtils;
import com.gavin.utils.Utility;

/**
 * ------------------------------
 * 分析sql结果
 * ------------------------------
 * @author wdm（l311576@sina.com）  @date 2018年9月17日
 * @version 1.0
 */
public class AnalyzedSQL {
	String sourceSQL;
	String formatSQL;// 去除取代值、r标签的SQL
	ArrayList<String> paraNames;
	
	/**
	 * 分析SQL语法 {}之内的为参数名，需要替换成? {{代表{字符 }}代表}字符
	 */
	public static AnalyzedSQL analyzeSourceSQL(String strSourceSQL, Model modelRequest) throws SQLException {
		AnalyzedSQL anaSQL = null;
		ArrayList<String> alParaName = new ArrayList<String>();
		StringBuilder strbSQL = new StringBuilder();
		StringBuilder strbFormatedSQL = new StringBuilder();
		int nState = 0;// 0 : {} 之外的字符, >1: {}之内字符.
		int nLength = strSourceSQL.length();
		StringBuilder strbParaName = new StringBuilder(nLength);
		int i = 0;
		while (i < nLength) {
			char ch = strSourceSQL.charAt(i);
			switch (ch) {
			case '\\':
				if (strSourceSQL.charAt(i + 1) == '\\') {// 字符\
					strbSQL.append("\\");
					strbFormatedSQL.append("\\");
					i += 2;
					break;
				} else if (strSourceSQL.charAt(i + 1) == '{') {// 字符{
					strbSQL.append("{");
					strbFormatedSQL.append("{");
					i += 2;
					break;
				} else if (strSourceSQL.charAt(i + 1) == '}') {// 字符}
					strbSQL.append("}");
					strbFormatedSQL.append("}");
					i += 2;
					break;
				}
				break;
			case '{':
				if (nState > 0 && i + 1 < nLength) {// 为普通字符
					strbParaName.append(ch);
					nState++;
					i += 1;
					break;
				}
				// 字段开始
				nState++;
				i++;
				break;
			case '}':
				if (nState > 1 && i + 1 < nLength) {// 为普通字符
					strbParaName.append(ch);
					nState--;
					i++;
					break;
				}
				// 在{}之内
				nState--;
				if (nState > 0) {// 由于嵌套的原因，{}尚未结束
					strbSQL.append("}");
					strbFormatedSQL.append("}");
					i++;
					break;
				}
				// {}已经结束
				if (strbParaName.length() == 0) {
					throw new SQLException("SQL syntax Error: " + strSourceSQL);
				}
				String strParaName = strbParaName.toString();
				String[] strsParaNameItemList = { strParaName };
				if (strParaName.indexOf("[") == strParaName.indexOf("]")) {
					strsParaNameItemList = Utility.splitString(strParaName, '|');// 使用替代值
				}

				if (strsParaNameItemList.length == 1) {// 普通ParaName
					strParaName = strsParaNameItemList[0];
					if (strParaName.startsWith("r:") == true) {// 直接替换SQL内容
						JObject jobj=modelRequest.getJObject(strbParaName.substring(2));
						if(jobj==null){
							throw new RuntimeException("invalid value: "+strbParaName);
						}
//						if("".equals(jobj.getValue())){
//							strbSQL.append("''");
//							strbFormatedSQL.append("''");
//						}else{
							strbSQL.append(jobj.getValue());
							strbFormatedSQL.append(jobj.getValue());
//						}
					} else {
						strbSQL.append("?");
						strbFormatedSQL.append("{" + strParaName + "}");
						alParaName.add(strParaName);
					}
				} else if (strsParaNameItemList.length == 2) {// 带有取代值的ParaName
					int nIndex = strsParaNameItemList[0].indexOf(':');
					if (nIndex >= 0) {// Item0为转义字段
						if (modelRequest.exists(strsParaNameItemList[0].substring(nIndex + 1))) {// ParaName存在
							strbSQL.append("?");
							strbFormatedSQL.append("{" + strsParaNameItemList[0] + "}");
							alParaName.add(strsParaNameItemList[0]);
						} else {// ParaName不存在，采用取代值
							if (strsParaNameItemList[1].equalsIgnoreCase("null")) {// 采用null值
								strbSQL.append("?");
								strbFormatedSQL.append("null");
								alParaName.add(null);
							} else {// 采用取代值
								if (modelRequest.exists(strsParaNameItemList[1]) == true) {// 值取代
									strbSQL.append("?");
									strbFormatedSQL.append("{" + strsParaNameItemList[1] + "}");
									alParaName.add(strsParaNameItemList[1]);
								} else if (strsParaNameItemList[1].indexOf(':') >= 0) {// 转义字段取代
									strbSQL.append("?");
									strbFormatedSQL.append("{" + strsParaNameItemList[1] + "}");
									alParaName.add(strsParaNameItemList[1]);
								} else {// 文本取代
									strbSQL.append(strsParaNameItemList[1]);
									strbFormatedSQL.append(strsParaNameItemList[1]);
								}
							}
						}
					} else {// Item0为普通字段
						if (modelRequest.get(strsParaNameItemList[0]) != null) {// ParaName存在
																				// 不为null
							strbSQL.append("?");
							strbFormatedSQL.append("{" + strsParaNameItemList[0] + "}");
							alParaName.add(strsParaNameItemList[0]);
						} else {// ParaName不存在，采用取代值
							if (strsParaNameItemList[1].equalsIgnoreCase("null")) {// 采用null值
								strbSQL.append("?");
								strbFormatedSQL.append("null");
								alParaName.add(null);
							} else {// 采用取代值
								if (modelRequest.get(strsParaNameItemList[1]) != null) {// 值取代
																						// ==
																						// true
									strbSQL.append("?");
									strbFormatedSQL.append("{" + strsParaNameItemList[1] + "}");
									alParaName.add(strsParaNameItemList[1]);
								} else if (strsParaNameItemList[1].indexOf(':') >= 0) {// 转义字段取代
									strbSQL.append("?");
									strbFormatedSQL.append("{" + strsParaNameItemList[1] + "}");
									alParaName.add(strsParaNameItemList[1]);
								} else {// 文本取代
									strbSQL.append(strsParaNameItemList[1]);
									strbFormatedSQL.append(strsParaNameItemList[1]);
								}
							}
						}
					}
				} else {
					throw new SQLException("SQL syntax Error: " + strSourceSQL);
				}
				strbParaName.setLength(0);

				i++;
				break;
			default:
				if (nState == 0) {// 在{}之外
					strbSQL.append(ch);
					strbFormatedSQL.append(ch);
				} else {
					strbParaName.append(ch);
				}
				i++;
				break;
			}
		}

		if (nState != 0) {
			throw new SQLException("SQL syntax Error: " + strSourceSQL);
		}
		
		anaSQL = new AnalyzedSQL();
		anaSQL.setSourceSQL(strbSQL.toString());
		anaSQL.setParaNames(alParaName);
		anaSQL.setFormatSQL(strbFormatedSQL.toString());
		return anaSQL;
	}

	
	final public static String getRealSQL(Model modelRequest, String strSQL) {
		StringBuilder strbLog = new StringBuilder();
		int nLength = strSQL.length();
		StringBuilder strbParaName = new StringBuilder(nLength);
		int nState = 0;// 0 : {} 之外的字符, 1: {}之内字符.
		int i = 0;
		while (i < nLength) {
			char ch = strSQL.charAt(i);
			switch (ch) {
			case '{':
				if (nState == 0) {// 在{}之外
					if (i + 1 < nLength && strSQL.charAt(i + 1) == '{') {// 为普通字符
						strbLog.append("{");
						i += 2;
					} else {// 字段开始
						nState = 1;
						i++;
					}
				} else {// 在{}之内，语法错误
					return strSQL;
				}
				break;
			case '}':
				if (nState == 0) {// 在{}之外
					if (i + 1 < nLength && strSQL.charAt(i + 1) == '}') {// 为普通字符
						strbLog.append("}");
						i++;
					} else {// 语法错误
						return strSQL;
					}
				} else {// 在{}之内，字段结束
					if (strbParaName.length() == 0) {// 语法错误
						return strSQL;
					}
					nState = 0;

					String strFieldId = strbParaName.toString();
					// int nIndex=strFieldId.indexOf(':');
					// if(nIndex>=0)
					// {
					// strFieldId=strFieldId.substring(nIndex+1);
					// }

					JObject objeFieldValue = null;
					try {
						objeFieldValue = ValueUtils.getObject(modelRequest, strFieldId);
					} catch (Exception e) {
					}
					Object objValue = null;
					if (objeFieldValue != null) {
						objValue = objeFieldValue.getValue();
					}
					if (objeFieldValue == null) {// 字段不存在
						strbLog.append('{' + strFieldId + '}');
					} else if (objValue instanceof String) {// 文本类型字段，加上引号
						strbLog.append('\'');
						strbLog.append(objValue);
						strbLog.append('\'');
					} else {// 其它类型字段
						strbLog.append(objValue);
					}
					strbParaName.setLength(0);
				}
				i++;
				break;
			default:
				if (nState == 0) {// 在{}之外
					strbLog.append(ch);
				} else {
					strbParaName.append(ch);
				}
				i++;
				break;
			}
		}

		if (nState == 1) {// 语法错误
			return strSQL;
		}

		return strbLog.toString();
	}


	public String getSourceSQL() {
		return sourceSQL;
	}
	public String getFormatSQL() {
		return formatSQL;
	}
	public ArrayList<String> getParaNames() {
		return paraNames;
	}
	public void setSourceSQL(String sourceSQL) {
		this.sourceSQL = sourceSQL;
	}
	public void setFormatSQL(String formatSQL) {
		this.formatSQL = formatSQL;
	}
	public void setParaNames(ArrayList<String> paraNames) {
		this.paraNames = paraNames;
	}
}